"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 故障&可靠性测试
Case Name   : 人为修改原配置文件中的审计目录为无权限,再恢复
Create At   : 2020/12/07
Owner       : @peilinqian
Description :
    1. 设置审计日志开关相关参数
    2. 进行事务操作；多次登陆数据库
    3. 修改配置文件中的审计目录为无权限
    4. 多次登陆数据库
Expect      :
    1. 设置审计日志开关相关参数成功
    2. 进行事务操作；多次登陆数据库成功，审计日志记录正确
    3. 修改配置文件中的审计目录为无权限成功
    4. 多次登陆数据库成功，pg日志记录报错，审计日志无记录
History     :
    Modified by @peilinqian 2021/8/4: 修改pg_log获取方式 优化打印信息
    Modified by @peilinqian 2021/8/17: 修改pg_log获取方式
    Modified by @peilinqian 2021/9/27: 优化期望，权限不影响审计
    Modified by @peilinqian 2021/10/19: 优化整个用例逻辑，审计目录权限影响审计及pg日志打印
    Modified by @li-xin12345 2024/1/22: 查询审计日志前增加等待时间及查询数据库时间，方便日志定位
    Modified by @li-xin12345 2024/2/26: 增加等待时间
"""
import os
import unittest
import time

from testcase.utils.Common import Common
from testcase.utils.CommonSH import *
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node


class ModifyAudit(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info('----Opengauss_Reliability_Db_System_Case056 start----')
        self.pri_dbuser = Node(node='PrimaryDbUser')
        self.pri_root = Node(node='PrimaryRoot')
        self.Constant = Constant()
        self.common = Common('PrimaryRoot')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.dbname = self.pri_dbuser.db_name
        self.constant = Constant()

    def test_main(self):
        self.log.info('----查询相关参数----')
        result = self.pri_sh.executDbSql('show audit_enabled;')
        self.log.info(f"audit_enabled is {result}")
        self.audit_enabled = result.strip().splitlines()[-2]
        result = self.pri_sh.executDbSql('show audit_login_logout;')
        self.log.info(f"audit_login_logout is {result}")
        self.audit_actor = result.strip().splitlines()[-2]
        result = self.pri_sh.executDbSql('show audit_directory;')
        self.log.info(f"audit_directory is {result}")
        self.audit_dir = result.strip().splitlines()[-2]
        result = self.pri_sh.executDbSql('show log_directory;')
        self.log.info(f"log_directory is {result}")
        self.log_dir = result.strip().splitlines()[-2]

        step_txt = '----step1:设置审计日志开关相关参数; expect:设置成功----'
        self.log.info(step_txt)
        mod_msg = self.pri_sh.executeGsguc('reload',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'audit_enabled = on')
        self.log.info(mod_msg)
        self.assertTrue(mod_msg, '执行失败:' + step_txt)
        mod_msg = self.pri_sh.executeGsguc('reload',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'audit_login_logout = 7')
        self.log.info(mod_msg)
        self.assertTrue(mod_msg, '执行失败:' + step_txt)

        step_txt = '----step2:进行事务操作；多次登陆数据库; expect:审计记录正常----'
        self.log.info(step_txt)
        db_start_time = self.pri_sh.executDbSql("SELECT current_time",
                                                self.dbname)
        self.log.info(db_start_time)
        start_time = self.pri_root.sh(f'date "+%Y-%m-%d %H:%M:%S"').result()
        for i in range(20):
            result = self.pri_sh.executDbSql(r'\q', self.dbname)
            self.log.info(result)
            self.assertIn('', result, '执行失败:' + step_txt)
        self.log.info('----查询审计结果----')
        time.sleep(120)
        db_end_time = self.pri_sh.executDbSql("SELECT current_time",
                                              self.dbname)
        self.log.info(db_end_time)
        end_time = self.pri_root.sh(f'date "+%Y-%m-%d %H:%M:%S"').result()
        result = self.pri_sh.executDbSql(
            f"select * from pg_query_audit('{start_time}', '{end_time}')",
            self.dbname)
        self.log.info(result)
        self.assertIn('login db', result, '执行失败:' + step_txt)
        self.log.info('----查询审计日志文件----')
        ls_cmd = f'ls -lt {self.audit_dir}'
        ls_result = self.pri_root.sh(ls_cmd).result()
        self.log.info(ls_result)

        step_txt = '----step3:修改配置文件中的审计目录为无权限; expect:修改成功----'
        self.log.info(step_txt)
        mod_cmd = f'chmod -R 000 {self.audit_dir}'
        self.log.info(mod_cmd)
        result = self.pri_root.sh(mod_cmd).result()
        self.log.info(result)
        self.log.info('----查询审计日志文件----')
        ls_cmd = f'ls -lt {self.audit_dir}'
        ls_result = self.pri_root.sh(ls_cmd).result()
        self.log.info(ls_result)

        step_txt = '----step4:多次登陆数据库成功; expect:pg日志记录报错，审计日志无记录----'
        self.log.info(step_txt)
        start_time = self.pri_root.sh(f'date "+%Y-%m-%d %H:%M:%S"').result()
        for i in range(20):
            result = self.pri_sh.executDbSql(r'\q', self.dbname)
            self.log.info(result)
            self.assertIn('', result, '执行失败:' + step_txt)
        end_time = self.pri_root.sh(f'date "+%Y-%m-%d %H:%M:%S"').result()
        self.log.info('----查看pg_log----')
        shell_cmd = f'''ls -t {self.log_dir} | head -1'''
        file_name = os.path.join(self.log_dir,
                                 self.pri_root.sh(shell_cmd).result())
        self.log.info(file_name)
        shell_cmd = f"cat {file_name} | " \
            f"grep '{self.Constant.PERMISSION_DENY_MSG}'"
        result = self.pri_root.sh(shell_cmd).result()
        self.log.info(result)
        self.assertIn(self.Constant.PERMISSION_DENY_MSG, result,
                      '执行失败:' + step_txt)
        self.log.info('----查看审计日志----')
        result = self.pri_sh.executDbSql(
            f"SELECT * FROM pg_query_audit('{start_time}', '{end_time}')",
            self.dbname)
        self.log.info(result)
        self.assertNotIn('login db', result, '执行失败:' + step_txt)
        self.assertIn('0 rows', result, '执行失败:' + step_txt)
        self.log.info('----查询审计日志文件----')
        ls_cmd = f'ls -lt {self.audit_dir}'
        ls_result = self.pri_root.sh(ls_cmd).result()
        self.log.info(ls_result)

    def tearDown(self):
        self.log.info('----this is teardown----')
        self.log.info('----恢复审计目录权限----')
        mod_cmd = f'chmod -R 700 {self.audit_dir}'
        self.log.info(mod_cmd)
        result = self.pri_root.sh(mod_cmd).result()
        self.log.info(result)
        self.log.info('----查询审计日志文件----')
        ls_cmd = f'ls -lt {self.audit_dir}'
        ls_result = self.pri_root.sh(ls_cmd).result()
        self.log.info(ls_result)

        self.log.info('----恢复审计相关参数----')
        self.pri_sh.executeGsguc('reload',
                                 self.constant.GSGUC_SUCCESS_MSG,
                                 f'audit_enabled = {self.audit_enabled}')
        self.pri_sh.executeGsguc('reload',
                                 self.constant.GSGUC_SUCCESS_MSG,
                                 f'audit_login_logout = {self.audit_actor}')

        self.log.info('----Opengauss_Reliability_Db_System_Case056 end----')